home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-06-24 | 16.8 KB | 384 lines | [TEXT/CCL ] |
- ; (c) Copyright 1990 by University of Massachusetts. All rights reserved.
- ; This software was conceived, designed, and written by Dan Suthers
- ; while supported by the National Science Foundation under grant number
- ; MDR 8751362, and by a fellowship from Apple Computer, Inc., Cupertino,
- ; CA. Partial support was also received from the Office of Naval Research
- ; under a University Research Initiative Grant, contract N00014-86-K-0764.
- ; Mr. Suthers created this software under his own initiative while in an
- ; academic relationship with the University of Massachusetts. The above
- ; copyright notice was a condition placed by University lawyers on approval
- ; of distribution of this software by Apple Computer, and is not meant to
- ; imply that this software was created in an employment or "work for hire"
- ; relationship between the University and Mr. Suthers.
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; File: DACTNS.lisp
- ; Author: Dan Suthers
- ; Created: 08-Aug-88 20:49:25
- ; Modified: 22-Jun-90 02:37:09 (Dan Suthers)
- ; Language: Common Lisp
- ; Package: DACTN
- ;
- ; Description: Defines recursive DACTNs and interpreter.
- ;
- ; (c) Copyright 1988, by Daniel D. Suthers
- ; Department of Computer and Information Science
- ; University of Massachusetts
- ; Amherst, Massachusetts 01003
- ;
- ; This software was conceived, designed, and written by Dan Suthers
- ; while supported by the National Science Foundation under grant number
- ; MDR 8751362, and by a fellowship from Apple Computer, Inc., Cupertino,
- ; CA. Partial support was also received from the Office of Naval Research
- ; under a University Research Initiative Grant, contract N00014-86-K-0764.
- ; I wish to acknowledge the generous support of Beverly Woolf, who obtained
- ; the above grants and encouraged me to pursue my own research interests in
- ; her lab. This work would not have been possible without the resources and
- ; stimulating environment of the Computer and Information Science department.
- ;
- ; Permission to use, modify, and distribute this software is granted subject
- ; to the following restrictions and understandings:
- ; 1. The file header, including this notice, shall be retained, and may be
- ; extended to include documentation of modifications to the software.
- ; 2. This material is for nonprofit educational and research purposes only.
- ; Users are requested, but not required, to inform Mr. Suthers of any
- ; noteworthy uses of this software.
- ; 3. Mr. Suthers and the University of Massachusetts make no warrantee or
- ; representation that the operation of this software will be error free,
- ; and are under no obligation to provide any services.
- ; 4. Any user of such software agrees to indemnify and hold harmless Mr.
- ; Suthers and the University of Massachusetts from all claims arising
- ; out of the use or misuse of this software, or arising out of any
- ; accident, injury, or damage whatsoever, and from all costs, counsel
- ; fees, and liabilities incurred in or about any such claim, action, or
- ; proceeding brought thereon.
- ; 5. All materials and reports developed as a consequence of the use of
- ; this software shall duly acknowledge such use, in accordance with
- ; the usual standards of acknowledging credit in academic research.
- ;
- ; Status: Usable, though I'd do it differently now.
- ; Needs compiler, better handling of re-entrant DACTNs.
- ;
- ; Changes:
- ; 04-Sep-88 Interpreter does not try to interpret DACTN with no start node.
- ; 26-Oct-88 Interpreter signals cerror if start node is specified but not
- ; defined in dactn-nodes; trace indented.
- ; 01-Nov-88 Updated for SM changes.
- ; 20-Dec-88 Added :edit-in-package :user to DST's.
- ;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Comments
- ;
- ; Nodes and arcs do not exist independently of the containing DACTN, so
- ; they are not represented as separate SM objects. In contrast, the tests
- ; on the arcs may be reused across DACTNs (they constitute a terminology
- ; for the conditional predicates), so are represented as DACTN-TESTs. Ditto
- ; for the actions.
- ;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- (in-package :DACTN)
-
- (export '(
- *trace-dactns*
-
- dactn
- initialize-dactns
- initialize-dactn
- interpret-dactn
- run-dactn
-
- dactn-test
- initialize-dactn-test
-
- dactn-action
- initialize-dactn-action
-
- ))
-
- (require :SM)
-
- ;;; To get past ccl compiler bug: it seems to hit sm:symbols before
- ;;; executing the require that creates the package, and gives a "no
- ;;; package WIND" error.
- (use-package :sm)
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- (defconstant *ARC-TYPES* '(:goto :exit))
-
- ;;; DACTN-NODEs are not implemented in SM as they conceptually do not
- ;;; exist outside of a given DACTN. See the documentation under DACTN.
- ;;; ARG-GEN not compiled so the structure will not contain unreadable forms.
-
- (defstruct (DACTN-NODE (:type list)) ; prints better to editor windows.
- (ACTION nil :type list)
- (ARG-GEN '(lambda (node) (declare (ignore node)) nil) :type list)
- (STATE '(:state nil) :type list)
- (ARCS nil :type list))
-
-
- (sm:dst (DACTN
- (:reusable nil)
- (:redefine t)
- (:sort-instances t)
- (:edit-in-package :user)
- (:after-edit (lambda (d) (initialize-dactn d)))
- (:comments "
- Discourse ACTion Networks, written to work with the View Retriever. Each
- network is defined by a set of nodes, where each node consists of an action
- and a set of arcs which are candidate ways to traverse out of the node. One
- node is designated the start node. DACTNs are compiled into an efficient
- function called by RUN-DACTN, but may be interpreted by INTERPRET-DACTN for
- debugging."))
-
- (NODES nil
- :type list
- :comments "
- An association list of node names to the definition of the node, which is
- a DACTN-NODE structure. (SM is not used for nodes because they are not
- visible outside of a given DACTN.) The latter structure contains the
- following slots:
- ACTION - (:action <action-name>) or (:dactn <dactn-name>).
- ARG-GEN - Lambda of one argument which generates the arguments to be
- given to the ACTION. The argument is a list of form (:state <state>).
- A setf of the second element will modify the node's state.
- STATE - A list of form (:state <state>). Initially <state> is nil.
- ARCS - An association list of DACTN-TESTs to arcs, which are of form
- (:goto <node-name>) or (:exit). Thus each entry in this list will look
- like (<dactn-test-name> <arc-action-keyword> [<argument>]). The arc
- in the first one whose CAR succeeds will be traversed.
- When a node is entered, (1) ARG-GEN is called on the state to generate a list
- of arguments; (2) the indicated ACTION is called on these arguments; (3) the
- list of ARCS is scanned to find the first one whose DACTN-TEST returns T when
- called on the state value; and (4) this arc is traversed by interpreting its
- keyword.")
-
- (START-NODE nil
- :type symbol
- :comments "
- The name of the start node for this DACTN. Its action is always executed.
- when the DACTN is run. It must be defined in NODES.")
-
- (FUNCTION #'(lambda (d ns)
- (error "Uncompiled DACTN-FUNCTION given ~S and ~S." d ns))
- :type function
- :computed t
- :comments "
- This is the compiled version of the DACTN, used to save the time of
- searching association lists and interpreting actions. INITIALIZE-DACTN
- fills this slot. The function takes no arguments, and executes the DACTN
- when funcalled.")
-
- (TYPE nil
- :type symbol
- :comments "
- This is a place to put a symbol categorizing the DACTN, to aid accessing and
- editing them. The use of this slot is application specific.")
-
- (COMMENTS "" :type string))
-
-
- (sm:dst (DACTN-TEST
- (:reusable nil)
- (:redefine t)
- (:sort-instances t)
- (:edit-in-package :user)
- (:after-edit (lambda (dt) (initialize-dactn-test dt)))
- (:comments "
- These are reusable tests of the state of the discourse and user models, used to
- determine which arc to take in a DACTN. They are given the current state value
- (the second element of the STATE slot) of the node as their only argument."))
-
- (FORM '(lambda (state) nil)
- :type list
- :comments "
- A lambda list of one argument, the STATE, which returns T iff whatever it tests
- for is true. Presumable some of these access the discourse and user models.")
-
- (COMPILED-FORM #'(lambda (state)
- (error "Uncompiled DACTN-TEST-FORM given ~S" state))
- :type function
- :computed t)
-
- (TYPE nil
- :type symbol
- :comments "
- This is a place to put a symbol categorizing the DACTN-TEST, to aid accessing and
- editing them. The use of this slot is application specific. See also INFO.")
-
- (INFO nil
- :comments "
- This is a place to put arbitrary info about the test. See also TYPE.")
-
- (COMMENTS "" :type string))
-
-
- (sm:dst (DACTN-ACTION
- (:reusable nil)
- (:redefine t)
- (:sort-instances t)
- (:edit-in-package :user)
- (:after-edit (lambda (da) (initialize-dactn-action da)))
- (:comments "
- Each of these defines an action in the underlying application. The names
- of these objects are the arguments to the :dactn-action specifier in DACTN
- arcs."))
-
- (FORM '(lambda (args) nil)
- :type list
- :comments "
- A lambda list of one argument which executes the intended action. The
- arguments are the list of arguments given to the action in the arc.")
-
-
- (COMPILED-FORM #'(lambda (args) (error "Uncompiled DACTN-ACTION given ~S" args))
- :type function
- :computed t)
-
- (TYPE nil
- :type symbol
- :comments "
- This is a place to put a symbol categorizing the DACTN-ACTION, to aid accessing and
- editing them. The use of this slot is application specific.")
-
- (INFO nil
- :comments "
- This is a place to put arbitrary info about the action. See also TYPE.")
-
- (COMMENTS "" :type string))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- (defun INITIALIZE-DACTNS ()
- (format *trace-output* "~&[Initializing DACTN-TESTs")
- (dolist (dt (sm:instances 'dactn-test))
- (declare (symbol dt))
- (initialize-dactn-test dt))
- (format *trace-output* "]~%[Initializing DACTN-ACTIONs")
- (dolist (da (sm:instances 'dactn-action))
- (declare (symbol da))
- (initialize-dactn-action da))
- (format *trace-output* "]~%[Initializing DACTNs")
- (dolist (d (sm:instances 'dactn))
- (declare (symbol d))
- (initialize-dactn d))
- (format *trace-output* "]"))
-
- (defun INITIALIZE-DACTN-TEST (dt)
- (let ((dactn-test (sm:gets 'dactn-test dt)))
- (setf (dactn-test-compiled-form dactn-test)
- (compile nil (dactn-test-form dactn-test)))))
-
- (defun INITIALIZE-DACTN-ACTION (da)
- (let ((dactn-action (sm:gets 'dactn-action da)))
- (setf (dactn-action-compiled-form dactn-action)
- (compile nil (dactn-action-form dactn-action)))))
-
- (defun INITIALIZE-DACTN (d) nil)
- ; (let ((dactn (sm:gets 'dactn d)))
- ; (dolist (name+struct (dactn-nodes dactn))
- ; (declare (cons name+struct))
- ; (setf (dactn-compiled-chooser dactn)
- ; (compile nil
- ; `(lambda ()
- ; (interpret-action
- ; (funcall (dactn-compiled-chooser (sm:gets 'dactn dactn))
- ; (mapcan #'(lambda (t+a)
- ; (declare (cons t+a))
- ; (if (funcall (dactn-test-compiled-form
- ; (sm:gets 'dactn-test (car t+a))))
- ; (list t+a)))
- ; (dactn-arcs (sm:gets 'dactn dactn))))))))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- (defvar *TRACE-DACTNS* nil)
-
- (defun INTERPRET-DACTN (dactn)
- "interpret-dactn <dactn> [Function]
- Interprets the dactn, without using the compiled dactn-function. Also
- uses uncompiled DACTN-TEST-FORM, DACTN-NODE-ARG-GEN, and DACTN-ACTION-FORM.
- Useful for debugging purposes."
- (check-type dactn symbol)
- (assert (sm:gets 'dactn dactn) (dactn) "~S is not a known DACTN." dactn)
- (let* ((dactn-struct (sm:gets 'dactn dactn))
- (start-node (dactn-start-node dactn-struct))
- (node-struct
- (cdr (assoc start-node (dactn-nodes dactn-struct)))))
- (declare (type dactn dactn-struct))
-
- ;; This would have saved me some time if it was here earlier ...
- (if (and start-node (null node-struct))
- (cerror "Will exit the DACTN but continue execution."
- "[INTERPRET-DACTN] Specified start node ~S for DACTN ~S is not defined."
- start-node dactn))
-
- (when node-struct
- (when *trace-dactns*
- (if (not (numberp *trace-dactns*)) (setq *trace-dactns* 0))
- (format *trace-output* "~&")
- (dotimes (x *trace-dactns*) (format *trace-output* " "))
- (format *trace-output* "[INTERPRET-DACTN] Starting ~A at ~A"
- dactn (dactn-start-node dactn-struct))
- (incf *trace-dactns*))
-
- ;; Interpretation consists of traversing arcs and interpreting nodes encountered.
- ;; If an :exit arc is executed in this dactn, returns to here immediately.
- (interpret-dactn-nodes dactn-struct node-struct)
-
- (when *trace-dactns*
- (decf *trace-dactns*)
- (format *trace-output* "~&")
- (dotimes (x *trace-dactns*) (format *trace-output* " "))
- (format *trace-output* "[INTERPRET-DACTN] Leaving ~A"
- dactn (dactn-start-node dactn-struct))))))
-
- (defun INTERPRET-DACTN-NODES (dactn-struct node-struct)
- (declare (type dactn dactn-struct) (type dactn-node node-struct))
- ;; Loop to repeat on new dactn nodes (saving cost of recursion).
- (loop
- ;; Run the action of the node.
- (case (first (dactn-node-action node-struct))
- ((nil) (cerror "Will ignore." "Unspecified action for node ~S." node-struct))
- ;; Action called on arguments generated by arg-gen, which tests & sets state.
- ((:action)
- (funcall (dactn-action-form (sm:gets 'dactn-action
- (second (dactn-node-action node-struct))))
- (funcall (dactn-node-arg-gen node-struct)
- (dactn-node-state node-struct))))
- ((:dactn) (interpret-dactn (second (dactn-node-action node-struct)))))
- ;; Find the first arc whose test succeeds when called on the node's state.
- (let ((arc (find-if #'(lambda (arc) (declare (list arc))
- (funcall (dactn-test-form (sm:gets 'dactn-test (first arc)))
- (dactn-node-state node-struct)))
- (dactn-node-arcs node-struct))))
- ;; Traverse this arc as specified by its keyword.
- (if arc
- (ecase (second arc)
- ;; Go To is to another node in the dactn: (<test> :goto <node>)
- ((:goto)
- (when *trace-dactns*
- (format *trace-output* "~&")
- (dotimes (x *trace-dactns*) (format *trace-output* " "))
- (format *trace-output* "[INTERPRET-DACTN-NODES] Going to node ~A"
- (third arc)))
- (setq node-struct (cdr (assoc (third arc) (dactn-nodes dactn-struct)))))
- ;; Exit returns from the dactn, so requires a throw.
- ((:exit) (return nil)))
- (return nil)))))
-
- ;;; Right now these parallel the INTERPRET- functions, but will be
- ;;; converted to simply invoke a truly compiled version, which simply:
- ;;; (funcall (dactn-function (sm:gets 'dactn dactn)) dactn)
-
- (defun RUN-DACTN (dactn)
- "run-dactn <dactn> [Function]
- Runs the DACTN, using its compiled functions."
- (check-type dactn symbol)
- (assert (sm:gets 'dactn dactn) (dactn) "~S is not a known DACTN.")
- (cerror "returns" "RUN-DACTN not implemented, use INTERPRET-DACTN for ~S." dactn))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (provide :DACTNS)
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; EOF